#include <stdio.h>
#include "esp_log.h"
#include "esp_check.h"
#include "driver/ledc.h"
#include "pca9557.h"
#include "driver/spi_master.h"
#include "esp_lcd_panel_io.h"
#include "esp_lcd_panel_vendor.h"
#include "esp_lcd_panel_ops.h"
#include "esp_lcd_types.h"


#define LCD_LEDC_CH LEDC_CHANNEL_0
#define LCD_SET_CS(data) pca9557_set(LCD_CS, data)
#define TAG "LCD"

esp_lcd_panel_io_handle_t io = NULL;
esp_lcd_panel_handle_t panel = NULL;

void lcd_set_color(int color)
{
    uint16_t *buffer = (uint16_t *)malloc(320 * sizeof(uint16_t));
    if (NULL == buffer)
    {
        ESP_LOGE("main", "Memory for bitmap is not enough");
    }
    else
    {
        for (size_t i = 0; i < 320; i++)
        {
            buffer[i] = color;
        }
        for (int y = 0; y < 240; y++)
        {
            esp_lcd_panel_draw_bitmap(panel, 0, y, 320, y + 1, buffer);
        }
        free(buffer);
    }
}

void lcd_set_backlight(int on)
{
    if (on > 100)
    {
        on = 100;
    }
    else if (on < 0)
    {
        on = 0;
    }
    uint32_t duty_cycle = (1023 * on) / 100;
    ledc_set_duty(LEDC_LOW_SPEED_MODE, LCD_LEDC_CH, duty_cycle);
    ledc_update_duty(LEDC_LOW_SPEED_MODE, LCD_LEDC_CH);
}

void lcd_init(void)
{
    // 1.backlight
    ledc_channel_config_t ledc_channel = {
        .gpio_num = CONFIG_LCD_BL_PIN,
        .speed_mode = LEDC_LOW_SPEED_MODE,
        .channel = LCD_LEDC_CH,
        .intr_type = LEDC_INTR_DISABLE,
        .timer_sel = LEDC_TIMER_0,
        .duty = 0,
        .hpoint = 0,
        .flags.output_invert = 1,
    };
    ledc_channel_config(&ledc_channel);
    
    ledc_timer_config_t ledc_timer = {
        .speed_mode = LEDC_LOW_SPEED_MODE,
        .timer_num = LEDC_TIMER_0,
        .duty_resolution = LEDC_TIMER_10_BIT,
        .freq_hz = 5000,
        .clk_cfg = LEDC_AUTO_CLK,
    };
    ledc_timer_config(&ledc_timer);

    // 2.SPI bus
    ESP_LOGI(TAG, "Initialize SPI bus");
    spi_bus_config_t buscfg = {
        .sclk_io_num = CONFIG_LCD_CLK_PIN,
        .mosi_io_num = CONFIG_LCD_MOSI_PIN,
        .miso_io_num = CONFIG_LCD_MISO_PIN,
        .quadwp_io_num = GPIO_NUM_NC,
        .quadhd_io_num = GPIO_NUM_NC,
        .max_transfer_sz = 240 * 320 * sizeof(uint16_t),
    };
    spi_bus_initialize(CONFIG_SPI_PORT, &buscfg, SPI_DMA_CH_AUTO);
    
    // 3.LCD panel
    ESP_LOGI(TAG, "Install panel IO");
    esp_lcd_panel_io_spi_config_t io_config = {
        .dc_gpio_num = CONFIG_LCD_DC_PIN,
        .cs_gpio_num = CONFIG_LCD_CS_PIN,
        .pclk_hz = CONFIG_SPI_SPEED_MHZ * 1000 * 1000,
        .lcd_cmd_bits = 8,
        .lcd_param_bits = 8,
        .spi_mode = 2,
        .trans_queue_depth = 10,
    };

    esp_lcd_new_panel_io_spi(CONFIG_SPI_PORT, &io_config, &io);
    // 4.LCD driver
    ESP_LOGI(TAG, "Install LCD driver");
    esp_lcd_panel_dev_config_t panel_config = {
        .reset_gpio_num = GPIO_NUM_NC,
        .rgb_ele_order = LCD_RGB_ELEMENT_ORDER_RGB,
        .bits_per_pixel = 16,
    };

    esp_lcd_new_panel_st7789(io, &panel_config, &panel);
    esp_lcd_panel_reset(panel);               // 液晶屏复位
    LCD_SET_CS(0);                            // 拉低CS引脚
    esp_lcd_panel_init(panel);                // 初始化配置寄存器
    esp_lcd_panel_invert_color(panel, true);  // 颜色反转
    esp_lcd_panel_swap_xy(panel, true);       // 显示翻转
    esp_lcd_panel_mirror(panel, true, false); // 镜像
    lcd_set_color(0xFFFF); 
    esp_lcd_panel_disp_on_off(panel, true);
    lcd_set_backlight(100);
}
